#include "ThreadCache.hpp"
#include "CentralCache.hpp"
void *ThreadCache::Allocate(size_t size)
{
    assert(size <= MAX_BYTES);
    // 计算对齐数
    size_t alignSize = SizeClass::RoundUp(size); // 内存对齐
    // 计算映射桶
    size_t index = SizeClass::Index(size); // 计算去哪个桶拿 映射桶号
    if (!_freeLists[index].Empty())
    {
        // 有对象就pop一个
        return _freeLists[index].Pop();
    }
    else
    {
        // 没有对象就从CentralCache获取，获取映射为index 大小为alignSize的对象
        return FetchFromCentralCache(index, alignSize);
    }
}
void ThreadCache::Deallocate(void *ptr, size_t size)
{
    assert(ptr);
    assert(size <= MAX_BYTES);

    // 计算桶号 将对象插入
    size_t index = SizeClass::Index(size);
    _freeLists[index].Push(ptr);

    // 当该桶链表长度大于一次批量申请的内存时就还一段List给CentralCache
    if (_freeLists[index].Size() >= _freeLists[index].MaxSize())
    {
        ListTooLong(_freeLists[index], size);
    }
}
void *ThreadCache::FetchFromCentralCache(size_t index, size_t size)
{
    // 慢开始调节算法
    // 1.最开始不会一次向central cache要太多 因为太多用不完会浪费
    // 2.如果对size大小不满足 batchNum 不断增长 直达上限
    // 3.size越大 一次向central cache 要的batchNum就越小
    // 4.size越小 一次向central cache 要的batchNum就越大
    size_t batchNum = std::min(_freeLists[index].MaxSize(), SizeClass::NumMoveSize(size));
    if (_freeLists[index].MaxSize() == batchNum)
    {
        _freeLists[index].MaxSize() += 1;
    }
    // 一段对象链表的头尾指针
    void *start = nullptr;
    void *end = nullptr;
    size_t actualNum = CentralCache::GetInstance()->FetchRangeObj(start, end, batchNum, size);
    // 实际可申请的num大小
    assert(actualNum > 0);
    if (actualNum == 1)
    {
        assert(start == end);
        // 如果是一个 则返回这个对象
        return start;
    }
    else
    {
        _freeLists[index].PushRange(NextObj(start), end, actualNum - 1);
        // 将一段对象链表插入到_freeLists[index]
        return start;
    }
}
void ThreadCache::ListTooLong(FreeList &list, size_t size)
{
    void *start = nullptr;
    void *end = nullptr;
    list.PopRange(start, end, list.MaxSize());
    // 取批量内存
    CentralCache::GetInstance()->ReleaseListToSpans(start, size);
    // 还给centralcache
}